package cn.ckx.coding.moudle.user.service.impl;

import cn.ckx.coding.common.constant.SexEnum;
import cn.ckx.coding.common.exception.BusinessError;
import cn.ckx.coding.common.exception.CommonErrors;
import cn.ckx.coding.common.exception.ErrorCodes;
import cn.ckx.coding.common.utils.http.HttpContextUtils;
import cn.ckx.coding.common.utils.redis.RedisKeys;
import cn.ckx.coding.moudle.user.dto.UserDTO;
import cn.ckx.coding.moudle.user.entity.UserEntity;
import cn.ckx.coding.moudle.user.event.UserRegisterEvent;
import cn.ckx.coding.moudle.user.mapper.UserMapper;
import cn.ckx.coding.moudle.user.service.UserService;
import cn.ckx.coding.properties.AppProperties;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * @ClassName UserServiceImpl
 * @Description
 * @Author kunxin.cai
 * @Date 2021/2/26
 * @Version 1.0
 **/
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Service("kxcoding-userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    private final AppProperties appProperties;

    private final ApplicationContext applicationContext;

    private static final String USER_CACHE =  RedisKeys.REDIS_BASE_NAME + ":userCache";

    private static final String ALL_USER_CACHE =  RedisKeys.REDIS_BASE_NAME + ":allUserCache";
    
    @Override
    public UserDTO loginByAccNum(String accNumber, String password) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(UserEntity::getAccNumber,accNumber);
        UserEntity userEntity = getOne(queryWrapper);
        if (Objects.isNull(userEntity)){
            throw BusinessError
                    .builder(ErrorCodes.BAD_REQUEST,"登录账号错误：%s")
                    .msgFormat(accNumber)
                    .build();
        }
        //加密密码，比较数值 此处不做处理

        //给response header塞入token    无token记录 token不做处理，先暂时存入为userId
        HttpContextUtils.getHttpServletResponse().setHeader(appProperties.getLogin().getUserId(),userEntity.getId());
        
        return UserDTO.fromEntity(userEntity); 
    }

    @Caching(
            put = {@CachePut(value = USER_CACHE, key = "#user.id")},
            evict = {@CacheEvict(value = ALL_USER_CACHE, allEntries = true)}
    )
    @Transactional(rollbackFor = Exception.class)
    @Override
    public UserDTO register(UserDTO user) {
        UserEntity userEntity = user.toEntity();
        if (Objects.isNull(userEntity.getSex())){
            userEntity.setSex(SexEnum.UNKNOWN);
        }
        if (save(userEntity)){
            
            //通知注册事件
            applicationContext.publishEvent(new UserRegisterEvent(userEntity));
            
            return UserDTO.fromEntity(userEntity, user);     
        }
        throw CommonErrors.UNEXPECT_ERROR.build();     
    }

    @Caching(
            put = {@CachePut(value = USER_CACHE, key = "#user.id")},
            evict = {@CacheEvict(value = ALL_USER_CACHE, allEntries = true)}
    )
    @Override
    public UserDTO update(UserDTO user) {
        return user;
    }

    @Caching(
            evict = {
                    @CacheEvict(value = USER_CACHE, key = "#id"),
                    @CacheEvict(value = ALL_USER_CACHE, allEntries = true)
            }
    )
    @Override
    public void delete(String id) {
        
    }

    @Cacheable(value = ALL_USER_CACHE, unless = "#result.size() == 0")
    @Override
    public List<UserDTO> listUser() {
        return null;
    }

    @Cacheable(value = USER_CACHE, key = "#id", unless="#result == null")
    @Override
    public UserDTO getById(String id) {
        return null;
    }


}
